﻿#include "FITKAbaqusHDF5AdaptorOutput.h"
#include "FITK_Kernel/FITKCore/FITKEnumTransformer.hpp"

#include "FITK_Interface/FITKInterfaceIO/FITKAbstractHDF5Reader.h"
#include "FITK_Interface/FITKInterfaceIO/FITKAbstractHDF5Writer.h"

#include "FITK_Interface/FITKInterfaceStructural/FITKAbaFieldOutput.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaHistoryOutput.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaStepManager.h"

#include "H5Cpp.h"

namespace IO
{
    QString FITKAbaqusHDF5AdaptorOutput::getAdaptorClass()
    {
        return "FITKAbaqusHDF5AdaptorOutput";
    }

    void FITKAbaqusHDF5AdaptorOutput::setStepManager(Interface::FITKAbaStepManager* stepManager)
    {
        _stepManager = stepManager;
    }

    bool FITKAbaqusHDF5AdaptorOutput::adaptR()
    {
        auto output = dynamic_cast<Interface::FITKAbaAbstractOutput*>(_dataObj);
        if (!_reader || !output || !_h5Group || !_stepManager) return false;
        bool isR = true;
        isR &= readOutput(output, *_h5Group);
        return isR;
    }

    bool FITKAbaqusHDF5AdaptorOutput::adaptW()
    {
        auto output = dynamic_cast<Interface::FITKAbaAbstractOutput*>(_dataObj);
        if (!_writer || !output || !_h5Group || !_stepManager) return false;
        bool isW = true;
        isW &= writeOutput(output, *_h5Group);
        return isW;
    }


    bool FITKAbaqusHDF5AdaptorOutput::readOutput(Interface::FITKAbaAbstractOutput* output, H5::Group& h5Group)
    {
        if (!output || !_stepManager) return false;
        bool isR = true;
        bool isValid = false;
        //写出基础信息
        isR &= readBoundaryLocation(output, h5Group);

        bool ActiveState = readBoolAttribute(h5Group, "ActiveState");
        output->setActiveState(ActiveState);

        //写出不同分析步的输出
        for (int i = 1; i < _stepManager->getDataCount(); ++i)
        {
            auto step = _stepManager->getDataByIndex(i);
            int stepID = step->getDataObjectID();
            if (!h5Group.nameExists(std::to_string(stepID))) return false;
            auto childH5Group = h5Group.openGroup(std::to_string(stepID));

            //base FITKAbaStepRelatedDataObject
            int CreatedStep = readIntAttribute(childH5Group, "CreatedStep");
            output->setCreatedStep(CreatedStep);

            int DeactiveStep = readIntAttribute(childH5Group, "DeactiveStep");
            output->setDeactiveStep(DeactiveStep);

            auto Domain = readStrAttribute(childH5Group, "Domain");
            //枚举转换字符
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputDomain> fitkODTypeTrafer;
            auto eDomain = fitkODTypeTrafer.fromString(QString::fromStdString(Domain), isValid);
            if (!isValid) return false;
            output->setDomain(eDomain);

            bool OutputForRebar = readBoolAttribute(childH5Group, "OutputForRebar");
            output->setOutputForRebar(OutputForRebar);

            auto OutputAtSectionPoints = readStrAttribute(childH5Group, "OutputAtSectionPoints");
            //枚举转换字符
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputAtSectionPoints> fitkOASPTypeTrafer;
            auto eOutputAtSectionPoints = fitkOASPTypeTrafer.fromString(QString::fromStdString(OutputAtSectionPoints), isValid);
            if (!isValid) return false;
            output->setOutputAtSectionPoints(eOutputAtSectionPoints);

            int Specify = readIntAttribute(childH5Group, "Specify");
            output->setSpecify(Specify);

            auto OutputFrequency = readStrAttribute(childH5Group, "OutputFrequency");
            //枚举转换字符
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputFrequency> fitkOFTypeTrafer;
            auto eOutputFrequency = fitkOFTypeTrafer.fromString(QString::fromStdString(OutputFrequency), isValid);
            if (!isValid) return false;
            output->setOutputFrequency(eOutputFrequency, stepID);

            auto OutputTiming = readStrAttribute(childH5Group, "OutputTiming");
            //枚举转换字符
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputTiming> fitkAOTTypeTrafer;
            auto eOutputTiming = fitkAOTTypeTrafer.fromString(QString::fromStdString(OutputTiming), isValid);
            if (!isValid) return false;
            output->setOutputTiming(eOutputTiming, stepID);

            auto SelectMode = readStrAttribute(childH5Group, "SelectMode");
            //枚举转换字符
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputVariablesSelectMode> fitkOVSTypeTrafer;
            auto eSelectMode = fitkOVSTypeTrafer.fromString(QString::fromStdString(SelectMode), isValid);
            if (!isValid) return false;
            output->setSelectMode(eSelectMode, stepID);

            int EveryNIncrements = readIntAttribute(childH5Group, "EveryNIncrements");
            output->setEvertyNIncrements(EveryNIncrements, stepID);

            int Intervals = readIntAttribute(childH5Group, "Intervals");
            output->setIntervals(Intervals, stepID);

            double XUnitsOfTime = readDoubleAttribute(childH5Group, "XUnitsOfTime");
            output->setXUnitsOfTime(XUnitsOfTime, stepID);

            //时间点
            int TimePointsId = readIntAttribute(childH5Group, "TimePointsId");
            output->setTimePointsId(TimePointsId, stepID);

            //模态列表，用于模态、屈曲分析步场输出频率按照指定模态进行输出的情况
            QList<int> ModeList;
            readIntDataSet(childH5Group, "ModeList", ModeList);
            output->setModeList(ModeList, stepID);

            QList<QString> variables;
            readStrDataSet(childH5Group, "SelectedVariables", variables);
            output->setSelectedVariables(variables, stepID);

            if (output->getOutputType() == Interface::FITKAbaAbstractOutput::FITKAbaOutputType::Field)
            {
                isR &= readFieldOutput(output, childH5Group);
            }
            else if (output->getOutputType() == Interface::FITKAbaAbstractOutput::FITKAbaOutputType::History)
            {
                isR &= readHistoryOutput(output, childH5Group);
            }
            else
            {
                return false;
            }

        }
        return isR;
    }

    bool FITKAbaqusHDF5AdaptorOutput::readFieldOutput(Interface::FITKAbaAbstractOutput* output, H5::Group& h5Group)
    {
        auto fieldOutput = dynamic_cast<Interface::FITKAbaFieldOutput*>(output);
        if (!fieldOutput) return false;

        if (!h5Group.attrExists("IncludeLocalCoordDirWhenAvailable")) return false;
        if (!h5Group.attrExists("ExteriorOnly")) return false;
        bool IncludeLocalCoordDirWhenAvailable = readBoolAttribute(h5Group, "IncludeLocalCoordDirWhenAvailable");
        fieldOutput->setIncludeLocalCoordDirWhenAvailable(IncludeLocalCoordDirWhenAvailable);
        bool ExteriorOnly = readBoolAttribute(h5Group, "ExteriorOnly");
        fieldOutput->setExteriorOnly(ExteriorOnly);
        return true;
    }

    bool FITKAbaqusHDF5AdaptorOutput::readHistoryOutput(Interface::FITKAbaAbstractOutput* output, H5::Group& h5Group)
    {
        auto HistoryOutput = dynamic_cast<Interface::FITKAbaHistoryOutput*>(output);
        if (!HistoryOutput) return false;
        return true;
    }

    bool FITKAbaqusHDF5AdaptorOutput::writeOutput(Interface::FITKAbaAbstractOutput* output, H5::Group& h5Group)
    {
        if (!output) return false;
        bool isW = true;
        bool isValid = false;

        std::string groupName = createParentAttribute(output, h5Group);
        if (groupName.empty())return false;

        _h5CreateGroup = h5Group.createGroup(groupName);

        //枚举转换字符 类型
        Core::FITKEnumTransfer<Interface::FITKAbaAbstractOutput::FITKAbaOutputType> fitkTTypeTrafer;
        auto Type = fitkTTypeTrafer.toStrting(output->getOutputType(), isValid);
        if (!isValid) return false;
        writeStrAttribute(_h5CreateGroup, "Type", Type.toStdString());

        //激活状态
        bool ActiveState = output->getActiveState();
        writeBoolAttribute(_h5CreateGroup, "ActiveState", &ActiveState);
        //写出不同分析步的输出
        for (int i = 1; i < _stepManager->getDataCount(); ++i)
        {
            auto step = _stepManager->getDataByIndex(i);
            int stepID = step->getDataObjectID();
            auto childGroup = _h5CreateGroup.createGroup(std::to_string(stepID));

            //base FITKAbaStepRelatedDataObject
            int CreatedStep = output->getCreatedStep();
            writeIntAttribute(childGroup, "CreatedStep", &CreatedStep);

            int DeactiveStep = output->getDeactiveStep();
            writeIntAttribute(childGroup, "DeactiveStep", &DeactiveStep);

            //枚举转换字符
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputDomain> fitkDDTypeTrafer;
            auto Domain = fitkDDTypeTrafer.toStrting(output->getDomain(), isValid);
            if (!isValid) return false;
            writeStrAttribute(childGroup, "Domain", Domain.toStdString());

            //钢筋的输出
            bool OutputForRebar = output->getOutputForRebar();
            writeBoolAttribute(childGroup, "OutputForRebar", &OutputForRebar);

            //梁、壳、复合层截面点输出
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputAtSectionPoints> fitkASTypeTrafer;
            auto OutputAtSectionPoints = fitkASTypeTrafer.toStrting(output->getOutputAtSectionPoints(), isValid);
            if (!isValid) return false;
            writeStrAttribute(childGroup, "OutputAtSectionPoints", OutputAtSectionPoints.toStdString());

            int Specify = output->getSpecify();
            writeIntAttribute(childGroup, "Specify", &Specify);

            //枚举转换字符
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputFrequency> fitkOFTypeTrafer;
            auto OutputFrequency = fitkOFTypeTrafer.toStrting(output->getOutputFrequency(stepID), isValid);
            if (!isValid) return false;
            writeStrAttribute(childGroup, "OutputFrequency", OutputFrequency.toStdString());

            //枚举转换字符
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputTiming> fitkOTTypeTrafer;
            auto OutputTiming = fitkOTTypeTrafer.toStrting(output->getOutputTiming(stepID), isValid);
            if (!isValid) return false;
            writeStrAttribute(childGroup, "OutputTiming", OutputTiming.toStdString());

            //枚举转换字符
            Core::FITKEnumTransfer<Interface::FITKAbaOutputVariable::OutputVariablesSelectMode> fitkITypeTrafer;
            auto SelectMode = fitkITypeTrafer.toStrting(output->getSelectMode(stepID), isValid);
            if (!isValid) return false;
            writeStrAttribute(childGroup, "SelectMode", SelectMode.toStdString());

            int EveryNIncrements = output->getEveryNIncrements(stepID);
            writeIntAttribute(childGroup, "EveryNIncrements", &EveryNIncrements);

            int Intervals = output->getIntervals(stepID);
            writeIntAttribute(childGroup, "Intervals", &Intervals);

            double XUnitsOfTime = output->getXUnitsOfTime(stepID);
            writeDoubleAttribute(childGroup, "XUnitsOfTime", &XUnitsOfTime);
            //时间点
            int TimePointsId = output->getTimePointsId(stepID);
            writeIntAttribute(childGroup, "TimePointsId", &TimePointsId);

            //模态列表，用于模态、屈曲分析步场输出频率按照指定模态进行输出的情况
            QList<int> ModeList = output->getModeList(stepID);
            writeIntDataSet(childGroup, "ModeList", ModeList);

            QList<QString> variables = output->getSelectedVariables(stepID);
            writeStrDataSet(childGroup, "SelectedVariables", variables);

            if (output->getOutputType() == Interface::FITKAbaAbstractOutput::FITKAbaOutputType::Field)
            {
                isW &= writeFieldOutput(output, childGroup);
            }
            else if (output->getOutputType() == Interface::FITKAbaAbstractOutput::FITKAbaOutputType::History)
            {
                isW &= writeHistoryOutput(output, childGroup);
            }
            else
            {
                return false;
            }

        }
        //写出基础信息
        isW &= writeBoundaryLocation(output, _h5CreateGroup);
        return isW;
    }

    bool FITKAbaqusHDF5AdaptorOutput::writeFieldOutput(Interface::FITKAbaAbstractOutput* output, H5::Group& h5Group)
    {
        auto fieldOutput = dynamic_cast<Interface::FITKAbaFieldOutput*>(output);
        if (!fieldOutput) return false;

        bool IncludeLocalCoordDirWhenAvailable = fieldOutput->getIncludeLocalCoordDirWhenAvailable();
        writeBoolAttribute(h5Group, "IncludeLocalCoordDirWhenAvailable", &IncludeLocalCoordDirWhenAvailable);

        bool ExteriorOnly = fieldOutput->getExteriorOnly();
        writeBoolAttribute(h5Group, "ExteriorOnly", &ExteriorOnly);
        return true;
    }

    bool FITKAbaqusHDF5AdaptorOutput::writeHistoryOutput(Interface::FITKAbaAbstractOutput* output, H5::Group& h5Group)
    {
        auto HistoryOutput = dynamic_cast<Interface::FITKAbaHistoryOutput*>(output);
        if (!HistoryOutput) return false;
        return true;
    }

}
